home *** CD-ROM | disk | FTP | other *** search
- /*
- * $Header: /private/postgres/src/support/RCS/postmaster.c,v 1.57 1992/08/12 02:47:20 mao Exp $
- *
- * POSTMASTER
- *
- * This program acts as a clearing house for requests to the
- * POSTGRES system. Frontend programs send a startup message
- * to the Postmaster and the postmaster uses the info in the
- * message to setup a backend process.
- *
- * Initialization:
- * The Postmaster sets up a few shared memory data structures
- * for the backends. It should at the very least initialize the
- * lock manager.
- *
- * Synchronization:
- * The Postmaster shares memory with the backends and will have to lock
- * the shared memory it accesses. The Postmaster should never block
- * on messages from clients.
- *
- * Garbage Collection:
- * The Postmaster cleans up after backends if they have an emergency
- * exit and/or core dump.
- *
- * Communication:
- *
- * Security:
- * There is none. Not a little bit.
- *
- * NOTES:
- *
- */
-
- #include <signal.h>
- #include <sys/file.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/time.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <netdb.h>
- #if !sprite
- #include <sys/un.h>
- #endif /* !sprite */
-
- #include "support/master.h"
- #include "utils/log.h"
- #include "storage/ipci.h"
- #include "tmp/pqcomm.h"
- #include "catalog/pg_user.h"
- #include "support/list.h"
-
- /* default permissions for opening files. */
- #define OPEN_PERMISSIONS (0666)
-
- List *ListGarbage; /* holds used list nodes for future use */
- short CommPort;
- char ShmIdStr[10];
- char ShmSizeStr[10];
- extern char *GetPGHome();
-
-
- #ifdef DBX_VERSION
- #define FORK() (0)
- #else
- #define FORK() fork()
- #endif
-
- /*
- * Info for garbage collection. Whenever a process dies, the Postmaster
- * cleans up after it. Currently, NO information is required for cleanup,
- * but I left this structure around in case that changed.
- */
- typedef struct bkend {
- int pid; /* process id of backend */
- } Backend;
-
- /* list of active backends. For garbage collection only now. */
- List *BackendList;
-
-
- /* list of ports associated with still open, but incomplete connections */
- List *PortList;
-
- /* for elog() messages. Port to send the message to. */
- Port *SendPort;
-
- /*
- * Default startup message parameters.
- */
- StartupPacket DefaultStartup;
-
- /*
- * IOList is used to setup file descriptors of backend processes.
- * Specify here how the descriptor set of the child (backend)
- * is different from the parent (Postmaster). I'm not sure
- * this stuff works all that well. I don't use any of the
- * sys logs.
- *
- * See descriptor reset for some notes.
- */
- typedef struct IOList {
- int fd;
- char *name;
- int mode;
- } IOList;
-
- #define DEFAULT ""
-
- IOList IO_List[] = {
- { 0, DEFAULT, (O_RDONLY) },
- { 1, DEFAULT, (O_WRONLY | O_APPEND | O_CREAT) },
- { 2, DEFAULT, (O_WRONLY | O_APPEND| O_CREAT) },
- { 0, NULL, 0 },
- };
-
- extern int NBuffers;
-
- extern char *optarg;
- extern int opterr;
- extern int optind;
- extern int errno;
-
- extern bool IsPostmaster;
-
- short PostPortName = DEF_PORT;
- short ActiveBackends = FALSE;
- int NextBackendId = 0x7fffffff; /* XXX not sure what this does */
-
- char *Usage = "postmaster [ -p port ] [ -b backend_pathname ] [ -d [level] ]\n";
- /*
- * Default Values
- */
- char Username[USER_NAMESIZE];
- char Dbname[64];
-
- /*
- * This is set by getpghome().
- */
- char *Home = "";
-
- int ServerSock = INVALID_SOCK; /* stream socket server */
-
- /*
- * Set by the -d option
- */
- int Debug = 0;
-
- /*
- * Set by the -o option
- */
- char ExtraOptions[ARGV_SIZE] = {0};
-
- /*
- * These globals control the behavior of the postmaster in case some
- * backend dumps core. Normally, it kills all peers of the dead backend
- * and reinitializes shared memory. By specifying -s or -n, we can have
- * the postmaster stop (rather than kill) peers and not reinitialize
- * shared data structures.
- */
- int Reinit = 1;
- int SendStop = 0;
-
- /*
- * postmaster.c - function prototypes (none of the funcs are public use)
- */
- int ServerLoop ARGS((int serverFd ));
- int ConnStartup ARGS((Port *port ));
- int ConnCreate ARGS((int serverFd , int *newFdP ));
- int PortDestroy ARGS((Port *port ));
- int pmdie ARGS((void ));
- int reaper ARGS((void ));
- int CleanupProc ARGS((int pid , int exitstatus ));
- int BackendStartup ARGS((Port *port , StartupPacket *packet , IOList *ioList ));
- int fixlead ARGS((char *str , char **dstP , int *sizeP ));
- int DoExec ARGS((char *execFile , char *database , int portFd , StartupPacket *pack ));
- int DescriptorReset ARGS((IOList *ioList ));
- int ExitPostmaster ARGS((int status ));
- int FindBackend ARGS((char *backend ));
- int ValidBackend ARGS((char *path ));
- int ReadObjDir ARGS((char *dir ));
- char *zalloc ARGS((unsigned long size ));
- #if 0
- int *CacheAlloc ARGS((unsigned int size ));
- #endif
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- char *getenv();
- char getopt();
- char opt;
- int serverMask;
- char *hostName;
- int status;
- int size;
- char sysLogPath[PATH_SIZE];
- char *sysLogPtr = sysLogPath;
- char dblogPath[PATH_SIZE];
- char *dblogPtr = dblogPath;
-
- /*
- * Initialize signal handlers. I took this from Dillon's code.
- * Not sure who made the decision about what signals to handle.
- */
- signal(SIGCHLD, reaper);
- signal(SIGTTIN, SIG_IGN);
- signal(SIGTTOU, SIG_IGN);
-
- signal(SIGHUP, pmdie);
- signal(SIGINT, pmdie);
- signal(SIGTERM, pmdie);
-
- ListHead(&ListGarbage); /* initialize ListGarbage */
-
- if (!(hostName = getenv("PGHOST"))) {
- hostName = "localhost";
- }
-
- opterr = 0;
- while ((opt = getopt(argc, argv, "B:b:dno:p:s")) != EOF) {
- switch (opt) {
- case 'B':
- /*
- * The number of buffers to create. Setting this
- * option means we have to start each backend with
- * a -B # to make sure they know how many buffers
- * were allocated.
- */
- NBuffers = atol(optarg);
- strcat(ExtraOptions, "-B ");
- strcat(ExtraOptions, optarg);
- break;
- case 'b':
- if (ValidBackend(optarg))
- strcpy(DefaultStartup.execFile, optarg);
- else
- fprintf(stderr, "%s %s",
- "Couldn't find the requested backend",
- "-- Using a default search path...\n");
- break;
- case 'd':
- if ((optind < argc) && *argv[optind] != '-') {
- Debug = atoi(argv[optind]);
- optind++;
- }
- else
- Debug = 1;
- break;
- case 'n':
- /* don't reinit shared mem after abnormal exit */
- Reinit = 0;
- break;
- case 'o':
- /*
- * Other options to pass to the backend on the
- * command line -- Useful only for debugging.
- */
- strcat(ExtraOptions, optarg);
- break;
- case 'p':
- PostPortName = (short)atoi(optarg);
- break;
- case 's':
- /*
- * In the event that some backend dumps core,
- * send SIGSTOP, rather than SIGUSR1, to all
- * its peers. This lets the wily post_hacker
- * collect core dumps from everyone.
- */
- SendStop = 1;
- break;
- default:
- perror("argument list");
- fprintf(stderr, "Usage: %s", Usage);
- exit(errno);
- break;
- }
- }
-
- IsPostmaster = true;
-
- Home = GetPGHome();
-
- /* default startup values */
- if (! DefaultStartup.execFile[0])
- FindBackend(DefaultStartup.execFile);
-
- strncpy(Username, getenv("USER"), USER_NAMESIZE);
- strcpy(DefaultStartup.user, Username);
- strcpy(DefaultStartup.database,Username);
- strcpy(Dbname, Username);
-
- status = StreamServerPort(hostName,PostPortName, &ServerSock);
- if (status != STATUS_OK) {
- elog(WARN,"PostMaster:cannot create stream port") ;
- exit(1);
- }
-
- /* set up shared memory and semaphores */
- EnableMemoryContext(TRUE);
- CreateSharedMemoryAndSemaphores(
- SystemPortAddressCreateIPCKey((SystemPortAddress)PostPortName));
-
- /*
- * Initialize the list of active backends. This list is only
- * used for garbage collecting the backend processes.
- */
- ListHead(&BackendList);
- ListHead(&PortList);
-
- status = ServerLoop(ServerSock);
- ExitPostmaster(status != STATUS_OK);
- }
-
- ServerLoop(serverFd)
- int serverFd;
- {
- int mask;
- int baseMask;
- int serverMask;
- int nSockets;
- int nSelected;
- int status;
- int dummy;
- List *curr;
-
- nSockets = ServerSock+1;
- baseMask = 1 << ServerSock;
- serverMask = baseMask;
-
- for (;;) {
- dummy = 0;
- mask = baseMask;
- if ((nSelected = select(nSockets, &mask, &dummy, &dummy, NULL)) < 0) {
- if (errno == EINTR)
- continue;
- elog(WARN,"Postmaster: select failed");
- return(STATUS_ERROR);
- }
-
- if (serverMask & mask) {
- int newFd;
- int newMask;
-
- status = ConnCreate(serverFd, &newFd);
-
- if (newFd >= nSockets)
- nSockets = newFd+1;
-
- /* read the new connection on the first pass */
- newMask = 1 << newFd;
- nSelected--;
- /* add the new connection to the baseMask */
- baseMask |= newMask;
- }
-
- ListForEach( curr, PortList, PortList) {
- ConnId connId; /* dummy argument */
- Port *port; /* port for I/O */
-
- port = (Port *) ListElem(curr);
-
- if (port->mask & mask) {
- nSelected--;
-
- /*
- * read the incoming packet into its packet buffer. Read the
- * connection id out of the packet so we know who the packet
- * is from.
- */
- status = PacketReceive(port, (Addr) &port->buf,
- NON_BLOCKING, &connId);
- switch (status) {
- case STATUS_OK:
- ConnStartup (port);
- ActiveBackends = TRUE;
- baseMask &= ~ port->mask;
- PortDestroy (port) ;
- ListDelete (curr) ;
- break;
-
- case STATUS_INVALID:
- baseMask &= ~ port->mask;
- PortDestroy (port) ;
- ListDelete (curr) ;
- break;
-
- case STATUS_NOT_DONE:
- break;
-
- case STATUS_ERROR:
- elog(WARN,"Postmaster: error receiving packet\n");
- return(STATUS_ERROR);
- }
- }
- }
- Assert (! nSelected);
- }
- /* shouldn't ever get here */
- }
-
- ConnStartup(port)
- Port *port; /* receiving port */
- {
- int status; /* procedure return code */
- MsgType msgType; /* type of message recieved */
- SeqNo seqno= INITIAL_SEQNO;/* dummy argument expected by packetData*/
- PacketLen bufSize; /* dummy argument */
- Addr buf; /* dummy argument */
-
- /*
- * Get the packet header information.
- */
- PacketData((Addr) &port->buf, &buf, &bufSize, &msgType, &seqno);
- if (msgType != STARTUP_MSG) {
- elog(WARN,"Postmaster: unrecognized message type\n");
- return(STATUS_ERROR);
- }
- if (BackendStartup(port, (StartupPacket *)&port->buf, IO_List) != STATUS_OK)
- {
- elog(WARN,"Postmaster: couldn't startup backend for client\n");
- return(STATUS_ERROR);
- }
- return(STATUS_OK);
- }
-
-
- /*
- * ConnCreate -- create a local connection data structure
- */
- ConnCreate(serverFd, newFdP)
- int serverFd;
- int *newFdP;
- {
- Connection *conn;
- int connId;
- int status;
- long currTime;
- int newFd;
- Port *port = (Port *) zalloc(sizeof(Port));
-
-
- status = StreamConnection(serverFd,&newFd,&port->addr);
-
- port->sock = newFd;
- port->mask = 1 << newFd;
-
- ListPush(PortList, port);
- *newFdP = newFd;
-
- /* in case of error message */
- SendPort = port;
-
- /*
- * If there was an error in the port creation, the connection
- * struct should be freed again.
- */
- if (status != STATUS_OK) {
- PortDestroy ( port ) ;
- }
-
- return(status);
- }
-
- PortDestroy(port)
- Port *port;
- {
- StreamClose( port->sock );
- free ((char *)port);
- }
-
- /*
- * pmdie -- signal handler for cleaning up after a kill signal.
- */
- pmdie()
- {
- exitpg(0);
- }
-
- /*
- * Reaper -- signal handler to cleanup after a backend (child) dies.
- *
- */
- reaper()
- {
- #ifdef linux
- int status;
- #else
- union wait status; /* backend exit status */
- #endif
- struct rusage ruse; /* resource usage structure */
- int pid; /* process id of dead backend */
-
- if (Debug)
- fprintf(stderr, "In reaper\n");
- while ((pid = wait3(&status, WNOHANG, &ruse)) > 0) {
- #ifdef linux
- (void) CleanupProc(pid,WEXITSTATUS(status));
- #else
- (void) CleanupProc(pid,status.w_status);
- #endif
- }
- }
-
- /*
- * CleanupProc -- cleanup after terminated backend.
- *
- * Remove all local state associated with backend.
- *
- * Dillon's note: should log child's exit status in the system log.
- */
- CleanupProc(pid,exitstatus)
- int pid;
- int exitstatus; /* child's exit status. */
- {
- List *curr;
- int sig;
-
- if (Debug)
- {
- fprintf(stderr, "In CleanUpProc - ");
- fprintf(stderr, "Backend with pid %d exited with status %d\n", pid, exitstatus);
- fflush(stderr);
- }
- /* -------------------------
- * If a backend dies in an ugly way (i.e. status not 0) then
- * we must signal all other backends to quickdie. If exit status
- * is zero we assume everything is hunky dory and simply remove the
- * backend from the active backend list.
- * -------------------------
- */
- if (!exitstatus)
- {
- ListForEach( curr, BackendList, BackendList)
- {
- Backend *bp = (Backend *) ListElem(curr);
-
- if (bp->pid == pid)
- {
- (void) free ((char *)bp);
- ListDelete(curr);
- break;
- }
- }
- return(STATUS_OK);
- }
- ListForEach( curr, BackendList, BackendList)
- {
- Backend *bp = (Backend *) ListElem(curr);
-
- /* -----------------
- * SIGUSR1 is the special signal that sez exit without exitpg
- * and let the user know what's going on. ProcSemaphoreKill()
- * cleans up the backends semaphore. If SendStop is set (-s on
- * the command line), then we send a SIGSTOP so that we can collect
- * core dumps from all backends by hand.
- * -----------------
- */
- if (SendStop)
- sig = SIGSTOP;
- else
- sig = SIGUSR1;
- if (bp->pid != pid)
- {
- if (Debug)
- fprintf(stderr, "Sending %s to process %d\n",
- (sig == SIGUSR1 ? "SIGUSR1" : "SIGSTOP"), bp->pid);
- kill(bp->pid, sig);
- ProcSemaphoreKill(bp->pid);
- }
- else
- ProcSemaphoreKill(bp->pid);
-
- (void) free ((char *)bp);
- ListDelete(curr);
- }
- /* -------------
- * Quasi_exit means run all of the on_exitpg routines but don't
- * acutally call exit(). The on_exit list of routines to do is
- * also truncated.
- *
- * Nothing up my sleeve here, ActiveBackends means that since the last time
- * we recreated shared memory and sems another frontend has requested and
- * received a connection and I have forked off another backend. This
- * prevents me from reinitializing shared stuff more than once for the
- * set of backends that caused the failure and were killed off.
- * ----------------
- */
- if (ActiveBackends == TRUE && Reinit)
- {
- if (Debug)
- fprintf(stderr, "Reinitializing shared memory and semaphores\n");
- quasi_exitpg();
- /* --------------
- * Recreate shared memory and semaphores.
- * --------------
- */
- CreateSharedMemoryAndSemaphores(
- SystemPortAddressCreateIPCKey((SystemPortAddress)PostPortName));
- ActiveBackends = FALSE;
- }
- return(STATUS_OK);
- }
-
- /*
- * BackendStartup -- startup backend process
- *
- * returns: STATUS_ERROR if the fork/exec failed, STATUS_OK
- * otherwise.
- *
- */
- BackendStartup(port, packet, ioList)
- Port *port;
- StartupPacket *packet; /* client's startup packet */
- IOList *ioList; /* io devices to setup */
- {
- int status; /* return status */
- Backend *bp; /* info to be used for backend cleanup */
- char dbData[PATH_SIZE];
- char efData[ARGV_SIZE];
- char *execFile;
- char *database; /* database after fixlead */
- int size; /* of fixlead string */
- int pid;
-
- database = dbData;
- execFile = efData;
-
- bp = (Backend *) zalloc(sizeof(Backend));
- if (! bp) {
- elog(FATAL,"Postmaster: cannot zalloc backend structure\n");
- ExitPostmaster(1);
- }
- ListPush(BackendList,bp);
-
- /*
- * If any of the arguments is missing, use the defaults.
- */
-
- /* Set up the backend as specified by the startup packet */
-
- if (* (packet->tty)) { /* Stdout/Stderr will become the tty file */
- ioList[1].name = packet->tty;
- ioList[2].name = packet->tty;
- }
-
- if (! * (packet->user))
- strcpy(packet->user,DefaultStartup.user);
-
- size = PATH_SIZE;
- if (! * (packet->database))
- strcpy(database,DefaultStartup.database);
- else
- (void) fixlead(packet->database,&database,&size);
-
- database = dbData;
-
- size = ARGV_SIZE;
- if (! * (packet->execFile))
- strcpy(execFile, DefaultStartup.execFile);
- else
- (void) fixlead(packet->execFile, &execFile, &size);
-
- execFile = efData;
-
- /*
- * Security: check the arguments. There should be an authorized
- * list of execFiles at the very least.
- */
-
- if ((pid = FORK()) == 0) {
- /* child:
- * use the ioList structure to setup your file descriptors and
- * then exec the file requested.
- */
- /*
- * These have to be made big enough!
- */
- char envEntry1[64];
- char envEntry2[64];
- char envEntry3[64];
-
- /* This goes to backend as command line arg!!!
- * dup2(port->sock,BACKEND_SOCK);
- */
- status = DescriptorReset(ioList);
- if (status) {
- _exit(1);
- }
-
- /* Set up the necessary environment variables for the backend
- * This should really be some sort of message....
- */
- #ifdef sprite
- {
- char c[50];
- sprintf(c, "%d", PostPortName);
- setenv("POSTPORT", c);
- sprintf(c, "%d", NextBackendId);
- setenv("POSTID", c);
- sprintf(c, "%s", packet->user);
- setenv("PG_USER", c);
- }
- #else
-
- sprintf(envEntry1, "POSTPORT=%d", PostPortName);
- putenv(envEntry1);
- sprintf(envEntry2, "POSTID=%d", NextBackendId);
- putenv(envEntry2);
- sprintf(envEntry3, "PG_USER=%s", packet->user);
- putenv(envEntry3);
- if (Debug) {
- printf("ENVIRONMENT: %s, %s, %s\n", envEntry1,envEntry2,envEntry3);
- }
-
- #endif /* sprite */
-
- if (! DoExec(execFile, database, port->sock,packet)) {
- return;
- }
-
- /* error -- exec has failed if we get here. */
- elog(FATAL,"Postmaster: DoExec failed for '%s'\n",DefaultStartup.execFile);
- _exit(1);
- }
-
- if (Debug)
- fprintf(stderr,
- "started '%s' for '%s' on '%s' (%d) pid (%d)\n",
- execFile,packet->user, database,port->sock, pid);
-
- if (pid < 0) {
- fprintf(stderr, "PostMaster: fork failed");
- return(STATUS_ERROR);
- }
- else
- bp->pid = pid;
-
- /* adjust backend counter */
- /* XXX Don't know why this is done, but for now backend needs it */
- NextBackendId -= 1;
-
- return(STATUS_OK);
- }
-
- /*
- * fixlead -- Expand special characters from path names.
- *
- * returns: TRUE if expansion occurred FALSE otherwise.
- * SIDE EFFECTS: copies str into dst
- *
- * NOTES: this does not use the sizeP parameter. It should
- * check for string overflow.
- */
- fixlead(str, dstP, sizeP)
- char **dstP, *str;
- int *sizeP;
- {
- char *dst = *dstP;
- int size = *sizeP;
- int status = TRUE;
-
- switch (*str) {
- /* carriage return == NULL */
- case '\n':
- return(FALSE);
-
- case '~':
-
- /* home directory of postgres installation */
- strcpy(dst, Home);
- break;
-
- case '&':
- strcpy(dst, Home);
- strcat(dst, "/data/base/");
- strcat(dst, Dbname);
- break;
-
- /* directory of database */
- case '%':
- strcpy(dst, Home);
- strcat(dst, "/data");
- break;
- /* directory of global data (should be '&/..') */
- default:
- *dst = '\0';
- status = FALSE;
- }
- if (status)
- str++;
-
- strncat(dst,str,size);
- size = strlen(dst);
- *dstP += size;
- *sizeP -= size;
- return(status);
- }
-
-
- /*
- * DoExec -- setup the arguments and make an execv system call.
- *
- * returns:
- * if not debugging, we shouldn't return at all (exec()).
- * if debugging, return 0.
- * if exec fails, return 1.
- */
- DoExec(execFile,database, portFd, pack)
- char *execFile,*database;
- StartupPacket *pack;
- int portFd;
- {
- int status;
- char portBuf[32];
- char debugBuf[32];
- char startDir[PATH_SIZE];
- char args[2*ARGV_SIZE];
-
- /*
- * Call backend with any/all desired options. These extra options
- * can either come from the front-end via the packet or from the
- * command line of the postmaster -o option.
- */
- args[0] = '\0';
- if (pack->options[0])
- strcpy(args, pack->options);
- if (ExtraOptions[0])
- strcat(args, ExtraOptions);
-
- status = 1;
-
- strcpy(startDir, Home);
- strcat(startDir, "/data/base/");
- strcat(startDir, pack->database);
- if (chdir(startDir))
- perror(startDir);
- /* If debugging requested pass the request along to the backend */
- if (Debug)
- sprintf(debugBuf, "-d %d", Debug);
- else
- sprintf(debugBuf, "-Q");
-
- sprintf(portBuf, "-P%d", portFd);
- if (Debug) {
- printf("The port file descriptor is %d\n", portFd);
- printf("execl: %s -p %s %s %s %s\n",
- execFile, debugBuf, portBuf, database, args);
- }
- if (!(*args)) {
- status =
- execl(execFile, execFile, "-p", debugBuf, portBuf, database, NULL);
- }
- else {
- status =
- execl(execFile, execFile, "-p", debugBuf, portBuf, args, database, NULL);
- }
- return(status);
- }
-
-
- /*
- * DescriptorReset -- reset the servers file descriptors to
- * match the configuration the new backend expects.
- *
- * This routine closes, stdin etc. It'll set up a log file.
- */
- DescriptorReset(ioList)
- IOList *ioList;
- {
- /*
- * For each element of the io list:
- * If the name is NONE, close the corresponding file descriptor.
- * If the name is DEFAULT, let the child inherit the parent's descriptors.
- * Otherwise, open the named descriptor.
- */
- for (;ioList->name;ioList++) {
- if (! strcmp(ioList->name, "NONE")) {
- close(ioList->fd);
- } else if (strcmp(ioList->name,DEFAULT)) {
- int tmpfd;
-
- if (! (tmpfd = open(ioList->name, ioList->mode, OPEN_PERMISSIONS))) {
- perror(ioList->name);
- fprintf(stderr,"PostMaster: child cannot open tty '%s'\n",ioList->name);
- return(STATUS_ERROR);
- }
- close(ioList->fd);
- dup2(tmpfd,ioList->fd);
- close(tmpfd);
- }
- }
- return(STATUS_OK);
- }
-
- /*
- * ExitPostmaster -- cleanup
- */
- ExitPostmaster(status)
- {
- /* should cleanup shared memory and kill all backends */
-
- /*
- * Not sure of the semantics here. When the Postmaster dies,
- * should the backends all be killed? probably not.
- */
- if (ServerSock != INVALID_SOCK)
- close(ServerSock);
- exitpg(status);
- }
-
- /* Delete this once the simple list implementation is ready */
-
- #define MAX_SIZE 450000
- #define MALLOC_MAGICNO 'M'
- #define PRINT_ALLOC(STR, STR1, NUM)
- #define DO_ALLOC(size)
- #define TOP_ADDR(str)
- int TotalCacheAlloc;
-
- int *
- CacheAlloc(size)
- unsigned int size;
- {
- char *tmp;
-
- Assert(size);
- Assert(size < MAX_SIZE);
- /* have to add four bytes because zalloc is going to align the space */
- tmp = (char *)zalloc(size+4);
- Assert(tmp);
- TOP_ADDR(tmp);
- PRINT_ALLOC("CacheAlloc",tmp,size);
- DO_ALLOC(TotalCacheAlloc += size);
-
- *(tmp+3) = MALLOC_MAGICNO;
- tmp += 4;
-
- return((int *)tmp);
- }
-
- FindBackend(backend)
- char *backend;
- {
- char path[PATH_SIZE];
- char objDir[PATH_SIZE];
- char *envVar;
- struct stat buf;
-
- /* check $POSTGRESHOME/bin/postgres */
-
- envVar = getenv("POSTGRESHOME");
- if (envVar) {
- strncpy(path, envVar, PATH_SIZE-21);
- strcat(path, "/bin/postgres");
- if (ValidBackend(path)) {
- strcpy(backend, path);
- return;
- }
- }
-
- /* check $POSTTREE/bin/postgres */
-
- envVar = getenv("POSTTREE");
- if (envVar) {
- strncpy(path, envVar, PATH_SIZE-21);
- strcat(path, "/bin/postgres");
- if (ValidBackend(path)) {
- strcpy(backend, path);
- return;
- }
- }
-
- /* check $POSTTREE/<obj.dir>/support/postgres */
-
- ReadObjDir(objDir);
-
- if (objDir[0]) {
- strncpy(path, objDir, PATH_SIZE-21);
- strcat(path, "/support/postgres");
- if (ValidBackend(path)) {
- strcpy(backend, path);
- return;
- }
- }
-
- /* check /usr/postgres/bin/postgres */
-
- strncpy(path, "/usr/postgres/bin/postgres", PATH_SIZE);
- if (ValidBackend(path)) {
- strcpy(backend, path);
- return;
- }
- fprintf(stderr,"Could not find a backend to execute -- giving up...\n");
- fprintf(stderr,"Have you set POSTGRESHOME in your environment?\n");
- fprintf(stderr,"Have you installed everything successfully?\n");
- exit(1);
- }
-
- ValidBackend(path)
- char *path;
- {
- struct stat buf;
-
- if ( stat(path, &buf) < 0 )
- return (FALSE);
- else if ( ! (buf.st_mode & S_IEXEC) )
- return (FALSE);
- else
- return (TRUE);
- }
-
- ReadObjDir(dir)
- char *dir;
- {
- FILE *fp;
- char buf[256];
- char tmpFile[32];
- char *bufptr;
- char *envPtr;
-
- /* Look for $POSTTREE/newconf/config.mk */
-
- if ((envPtr = getenv("POSTTREE")) == NULL)
- {
- *dir = '\0';
- return;
- }
-
- /* make a temporary file */
- sprintf(tmpFile, "/tmp/pm.%d", getpid());
-
- sprintf(buf,
- "fgrep OD= %s/newconf/config.mk | sed -e \'s/OD=\t//\' > %s",
- envPtr,
- tmpFile);
-
- system( buf );
-
- if ((fp = fopen(tmpFile, "r")) == NULL) {
- *dir = '\0';
- return;
- }
-
- fgets(buf, 255, fp);
-
- /* kill the annoying \n fgets always puts at the end of the line */
-
- bufptr = (char *)index(buf, '\n');
- if (bufptr)
- *bufptr = (char)NULL;
- strncpy(dir, buf, PATH_SIZE);
-
- fclose(fp);
- unlink(tmpFile);
- return;
- }
-
- char *
- zalloc(size)
-
- unsigned long size;
-
- {
- char *t;
-
- t = (char *) malloc(size);
- bzero(t, size);
- return(t);
- }
-